我们有一个使用 UTL_FILE 创建 CSV 文件的过程。(env 是 Oracle 11.2.0.1 和 RHEL 6.4)到目前为止,我们将该 CSV 文件存储到系统oracle
(oracle 所有者)用户主目录 (/home/oracle/csv/) 中。它工作正常,但现在我们需要将 CSV 文件存储到不同的系统用户主目录(例如reports
系统用户主目录 (/home/reports/csv/))
因此,我们将oracle
用户添加到该组reports
作为其次要组,然后将reports
主页权限更改为他和他的所有组都可以访问。
# id oracle
uid=500(oracle) gid=500(oracle) grupos=500(oracle),502(reports)
# id reports
uid=502(reports) gid=502(reports) grupos=502(reports)
# chmod 770 /home/reports
# ls -la /home/reports/
total 52
drwxrwx--- 8 reports reports 4096 oct 3 12:58 .
drwxr-xr-x. 5 root root 4096 oct 2 11:05 ..
drwxrwxrwx 2 reports reports 4096 oct 3 12:59 csv
有了这个,登录到系统,oracle
我可以写入,读取和执行文件到reports
's home。
# su - oracle
oracle ~$ touch /home/reports/csv/test.txt
oracle ~$ ls -la /home/reports/csv/test.txt
total 8
-rw-rw-r-- 1 oracle oracle 0 oct 3 17:51 test.txt
现在,据我所知(甲骨文的文档说),这应该有效,但它没有......根本没有。 如果我用 sqlplus 在本地连接,它可以工作。但是如果我从远程机器或通过监听器连接,我不会!
我将向您展示: 与 sqlplus 的本地连接:
oracle ~$ export ORACLE_SID=MYDB
oracle ~$ sqlplus -S informes
Introduzca la contraseña:
select a.directory_name,
a.directory_path,
b.grantee,
b.privilege
from all_directories a,
all_tab_privs b
where a.directory_name = b.table_name
and DIRECTORY_NAME='CSVFOLDER';
DIRECTORY_NAME DIRECTORY_PATH GRANTEE PRIVILEGE
------------------------------ -------------------- --------- ---------
CSVFOLDER /home/reports/csv INFORMES READ
CSVFOLDER /home/reports/csv INFORMES WRITE
show user
USER es "INFORMES"
declare
output_fich utl_file.file_type;
begin
output_fich := utl_file.fopen('CSVFOLDER','testfile.csv','W');
utl_file.put_line (output_fich, 'test line');
utl_file.fclose(output_fich);
end;
/
Procedimiento PL/SQL terminado correctamente.
host ls -la /home/reports/csv/testfile.csv
-rw-rw-r-- 1 oracle oracle 10 oct 3 18:20 /home/informesestados/tmp/testfile.csv
host rm /home/reports/csv/testfile.csv
现在,让我们再次尝试通过侦听器连接 让我们看看我的 tnsnames 指向哪里:
oracle ~$ cat $ORACLE_HOME/network/admin/tnsnames.ora | grep MYDB
MYDB = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = FR-BD1-tmp)(PORT = 1522))) (CONNECT_DATA = (SERVICE_NAME = MYDB)))
oracle ~$ ping FR-BD1-tmp
PING fr-bd1-tmp (192.168.78.3) 56(84) bytes of data.
64 bytes from fr-bd1-tmp (192.168.78.3): icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from fr-bd1-tmp (192.168.78.3): icmp_seq=2 ttl=64 time=0.025 ms
^C
--- fr-bd1-tmp ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1386ms
rtt min/avg/max/mdev = 0.025/0.036/0.047/0.011 ms
oracle ~$ /sbin/ifconfig | grep "inet addr"
inet addr:192.168.78.3 Bcast:192.168.78.255 Mask:255.255.255.0
oracle ~$ lsnrctl services LISTENER_MYBD
LSNRCTL for Linux: Version 11.2.0.1.0 - Production on 03-OCT-2013 18:33:04
Copyright (c) 1991, 2009, Oracle. All rights reserved.
Conectándose a (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=fr-bd1-tmp)(PORT=1522)))
Resumen de Servicios...
El servicio "mydb" tiene 1 instancia(s).
La instancia "mydb", con estado READY, tiene 1 manejador(es) para este servicio...
Manejador(es):
"DEDICATED" establecido:45 rechazado:0
LOCAL SERVER
El servicio "mydb_node1" tiene 1 instancia(s).
La instancia "mydb", con estado READY, tiene 1 manejador(es) para este servicio...
Manejador(es):
"DEDICATED" establecido:3 rechazado:0 estado:ready
LOCAL SERVER
El comando ha terminado correctamente
oracle ~$ sqlplus -S informes@mydb
Introduzca la contraseña:
select a.directory_name,
a.directory_path,
b.grantee,
b.privilege
from all_directories a,
all_tab_privs b
where a.directory_name = b.table_name
and DIRECTORY_NAME='CSVFOLDER';
DIRECTORY_NAME DIRECTORY_PATH GRANTEE PRIVILEGE
------------------------------ -------------------- --------- ---------
CSVFOLDER /home/reports/csv INFORMES READ
CSVFOLDER /home/reports/csv INFORMES WRITE
show user
USER es "INFORMES"
declare
output_fich utl_file.file_type;
begin
output_fich := utl_file.fopen('INFORMES','testfile.csv','W');
utl_file.put_line (output_fich, 'test line');
utl_file.fclose(output_fich);
end;
/
declare
*
ERROR en línea 1:
ORA-29283: operación de archivo no válida
ORA-06512: en "SYS.UTL_FILE", línea 536
ORA-29283: operación de archivo no válida
ORA-06512: en línea 4
现在,如果我将reports
's home 权限更改为所有人都可以访问,则通过侦听器连接的 UTL_FILE 过程可以正常工作!
# chmod 777 /home/reports
# ls -la /home/reports/
total 52
drwxrwxrwx 8 reports reports 4096 oct 3 12:58 .
drwxr-xr-x. 5 root root 4096 oct 2 11:05 ..
drwxrwxrwx 2 reports reports 4096 oct 3 12:59 csv
# su - oracle
oracle ~$ sqlplus -S informes@mydb
Introduzca la contraseña:
declare
output_fich utl_file.file_type;
begin
output_fich := utl_file.fopen('CSVFOLDER','testfile.csv','W');
utl_file.put_line (output_fich, 'test line');
utl_file.fclose(output_fich);
end;
/
Procedimiento PL/SQL terminado correctamente.
host ls -la /home/reports/csv/testfile.csv
-rw-rw-r-- 1 oracle oracle 10 oct 3 18:59 /home/informesestados/tmp/testfile.csv
???
我不明白为什么会有这种行为。正如甲骨文的文档所说:
( http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/u_file.htm )
在 UNIX 系统上,由 FOPEN 函数创建的文件的所有者是运行实例的影子进程的所有者
影子进程的所有者在两种方法中都相同(即“oracle”系统用户),所以,.. 为什么会这样?
有人有线索吗?我错过了什么吗?
这是 Unix 系统上的预期行为。进程的有效用户 ID 允许读/写文件或其有效的主要或有效的辅助组 ID 允许读/写文件
如果您登录到 unix 系统,则有效用户 id、有效组 id 和有效辅助组 id 是为您在该系统上的登录用户定义的 id(在 /etc/passwd 或任何地方)。如果一个unix进程创建了一个新进程,那么新进程会从创建进程继承这个id。
Oracle 影子进程是对应于 oracle 会话的 unix 进程。如果您使用网络连接登录数据库,则此影子进程由侦听器进程创建。如果您向 oracle unix 用户添加新的辅助组 ID,这不会更改正在运行的侦听器进程的有效 ID,因此所有新创建的进程都具有与添加新辅助之前创建的进程相同的有效用户/组 ID团体。
但是,如果您在向 oracle 用户添加新的辅助组 id 后登录系统,您的登录会话将有这个额外的有效辅助组 id,如果您停止并启动侦听器进程,它也会有额外的有效辅助组 id . 新的侦听器进程创建的影子进程也是如此。
如果侦听器进程在添加新的辅助组 id 后被另一个进程停止,但在添加新的辅助组 id 后该其他进程没有重新启动,则侦听器不会将新的辅助组 id 作为有效的辅助组 id,即使他被重新启动,因为启动侦听器进程的进程没有新的辅助 id 作为有效的辅助 id。如果您通过某个集群进程重新启动侦听器进程,则可能会发生这种情况。在这种情况下,必须先重新启动此集群进程,然后才能重新启动侦听器进程,以使新添加的辅助组 id 生效。
如果您使用 sqlplus 进行本地连接,则影子进程由 sqlplus 生成,而不是由侦听器进程生成。但是 sqlplus 进程具有由您的登录会话继承的有效用户/组 ID。那么您在添加新的辅助组后是否登录,那么影子进程将具有此辅助组 ID。如果在将辅助组添加到 oracle 用户之前已经建立了登录,那么您的 unix 会话的所有新本地 sqlplus 连接(= 影子进程)也不会将此额外的辅助组 ID 作为有效的辅助组 ID。
正如 Colin 't Hart 和 Phil 在评论中建议的那样,我不得不重新启动监听器。这就是问题所在!
非常感谢,我整天都被困在这个问题上。
问候
更新
最近,我在使用调度程序执行的过程中遇到了类似的情况。在这种情况下,影子进程由作业协调进程 (CJQ0) 生成。在这里,您将需要重新启动整个数据库(您可以杀死 CJQ0,但随后它由进程监视器生成,有同样的问题)。
作为一种解决方法,您可以使用 linux 访问控制列表
setfacl
。有了它,该过程无需重新启动即可重新加载组成员资格。