最近有个朋友提了一个问题,她们有套11g的数据库升级到19c,但是某个脚本中使用了utl_file进行文件操作,在11g中设置了UTL_FILE_DIR参数,而19c中没这个参数了,如果强制设置,就提示该参数obsolete,废弃了,
相应地,脚本中这段逻辑,
UTL_FILE.FOPEN('/home/oracle/', 'test.txt', 'w');
提示如下错误
SQL 错误 [29280] [99999]: ORA-29280: 无效的目录对象
ORA-06512: 在 "SYS.UTL_FILE", line X
ORA-06512: 在 "SYS.UTL_FILE", line X
ORA-06512: 在 line X
ORA-29280错误的解释,这是无效的directory对象名称,说的就是FOPEN函数的第一个参数值”/home/oracle/”,
SQL> !oerr ora 29280
29280, 00000, "invalid directory object"
// *Cause: A corresponding directory object does not exist.
// *Action: Correct the directory object parameter, or create a corresponding
// directory object with the CREATE DIRECTORY command.
我们通过官方文档可以找到一些线索,11g的《Reference》说UTL_FILE_DIR的意思是可以设置PL/SQL中操作文件的目录路径,特意强调了所有的用户都可以读写这个参数定义的文件,
UTL_FILE包的使用可参见《Oracle数据导出新选择》,但是当时确实没太注意到UTL_FILE.FOPEN函数的第一个参数值,
UTL_FILE.FOPEN('UTL_FILE_DIR', 'test.txt', 'w');
从11g的文档,我们可以看到,UTL_FILE的作用就是提供客户端和服务端文件访问的权限,能访问的目录范围就是UTL_FILE_DIR参数给定义的,但是通过参数控制可访问的目录,存在安全隐患,一个是参数和用户本身其实并没有强关联,只要定义了,任何用户都能用,另外这个参数是个静态参数,修改生效,需要重启数据库,因此,不推荐使用UTL_FILE_DIR,而是推荐使用Oracle的directory目录对象,它可以提供更加弹性和细粒度的权限控制,而且支持动态调整,
Connor McDonald曾写过这篇文章,提到了让UTL_FILE使用directory对象可以提升安全性的一些原因,有兴趣的朋友,可以了解下,https://connor-mcdonald.com/2018/06/27/utl_file_dir-and-18c/
FOPEN函数的第一个参数官方解释是location,文件目录的位置,11g中要求是个directory对象,并且必须是大写,同时要求必须给执行FOPEN的用户对这个目录对象的读权限,
因此,11g中支持这种跟着操作系统文件路径的逻辑,
UTL_FILE.FOPEN('/home/oracle/', 'test.txt', 'w');
但是,从18c开始,UTL_FILE_DIR参数就给废弃了,取而代之的是推荐设置directory对象名称,
Desupport of UTL_FILE_DIR Initialization Parameter
Starting in Oracle Database 18c, the UTL_FILE_DIR parameter is no longer supported. Instead, specify the name of a directory object.
因此,正确使用UTL_FILE,第一步就是创建目录对象,并进行授权,
create directory test_dir as '/home/oracle';
grant read, write on directory test_dir to bisal;
如果要模拟测试,可以用这段PL/SQL,
declare
f utl_file.file_type;
begin
f := utl_file.fopen('/home/oracle','od.csv','W');
utl_file.fclose_all;
end;
/
执行会提示
SQL 错误 [29280] [99999]: ORA-29280: 无效的目录对象
ORA-06512: 在 "SYS.UTL_FILE", line X
ORA-06512: 在 "SYS.UTL_FILE", line X
ORA-06512: 在 line X
如果改成directory对象名称作为第一个参数,就可以正常执行,
declare
f utl_file.file_type;
begin
f := utl_file.fopen('TEST_DIR','od.csv','W');
utl_file.fclose_all;
end;
/
因此,针对从11g升级到19c,并且使用”/home/oracle”这种操作系统路径作为FOPEN参数的脚本逻辑,就得进行改造,换成directory对象名称,才可以正常执行。
这种废弃参数的场景,一般情况下,Oracle会在前几个版本中就会提到,但是不会明确这个参数具体会在什么版本真正废弃,给了你改造缓冲,因此了解一些和你的应用逻辑相关的Oracle知识还是有用的,至少能未雨绸缪,但这其实就对开发人员提高了要求,不能将数据库看做黑盒,还是得能有针对性地了解数据库,才能更好地运用数据库提供的特性,这算是相辅相成的道理。
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/136449.html