回到开始:这是我的startup.pl文件:
$ENV{'NLS_LANG'}='AMERICAN_AMERICA.AL32UTF8';
$ENV{'ORACLE_HOME'}='/opt/oracle/OraHome1';
use DBI ();
use DBD::Oracle ();
这是我的测试程序:
#!/usr/bin/perl
require "startup.pl" unless defined $ENV{'ORACLE_HOME'};
use DBI;
use DBD::Oracle;
print "Content-type: text/plain\n\n";
print "connecting: \n";
my $dbh=DBI->connect("dbi:Oracle:mydb", 'username', 'password');
print "connected! \n";
在命令行中运行此代码可以正常工作。在 CGI 脚本中运行也能正常工作。但是,在 mod_perl 中运行会导致 Apache 崩溃:
[Wed Dec 04 16:38:01 2013] [notice] Apache/2.2.15 (Unix) DAV/2 PHP/5.3.3 mod_wsgi/3.2 Python/2.6.6 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations
[Wed Dec 04 16:38:28 2013] [notice] child pid 25756 exit signal Segmentation fault (11)
执行httpd进程上的strace,结果如下:
connect(21, {sa_family=AF_INET, sin_port=htons(389), sin_addr=inet_addr("10.250.52.237")}, 16) = 0
write(21, "0\f\2\1\1`\7\2\1\2\4\0\200\0", 14) = 14
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, -1) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\0\20\2\1", 8) = 8
read(21, "\1a\204\0\0\0\7\n\1\0\4\0\4\0", 14) = 14
write(21, "0\201\226\2\1\2c\201\220\0042cn=bpas_p,cn=OracleCo"..., 153) = 153
poll([{fd=21, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 10000) = 1 ([{fd=21, revents=POLLIN}])
read(21, "0\204\0\0\1{\2\1", 8) = 8
read(21, "\2d\204\0\0\1r\0040cn=bpas_p,cn=OracleCont"..., 377) = 377
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
显然,httpd 在与 10.250.52.237:389 通信时崩溃了,这是 oracle 名称解析器的 ldap 端口。
我的标准 sqlnet.ora 如下:
NAMES.DIRECTORY_PATH = (LDAP, ONAMES, TNSNAMES)
NAMES.DEFAULT_DOMAIN = xxx.yyyy.zzz
NAMES.PREFERRED_SERVERS =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = oranames01.yyyy.zzz)(PORT = 1501))
(ADDRESS = (PROTOCOL = TCP)(HOST = oranames02.yyyy.zzz)(PORT = 1502))
)
这是我的ldap.ora文件:
DIRECTORY_SERVERS = (oranames01.yyyy.zzz:389:636, oranames02.yyyy.zzz:389:636)
DEFAULT_ADMIN_CONTEXT = "dc=xxx, dc=yyyy, dc=zzz"
DIRECTORY_SERVER_TYPE = OID
从strace dump中获取的地址(10.250.52.237)是oranames01.yyyy.zzz的IP地址。
如果我从sqlnet.ora中删除LDAP适配器
NAMES.DIRECTORY_PATH = (ONAMES, TNSNAMES)
并将数据库连接字符串放入tnsnames.ora文件中。
mydb.xxx.yyyy.zzz=(DESCRIPTION=(SOURCE_ROUTE=OFF)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=ivorapo01.xxx.yyyy.zzz)(PORT=15350)))(CONNECT_DATA=(SERVICE_NAME=mydb.xxx.yyyy.zzz)(FAILOVER_MODE =(TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 1))))
所有的功能都很好 - 命令行,cgi perl和mod_perl。
显然,mod_perl和LDAP名称解析器的结合存在一些问题。
我在Fedora 14系统上遇到了这个问题,使用的是apache 2.2.17和Oracle客户端10.2.0.1.0,最近在CentOs 6.5上进行了新安装,使用的是apache 2.2.15和oracle客户端12.1.0.1.0。搜索mod_perl和oracle会显示一些关于ORACLE_HOME设置太晚的结果(我也有这个问题,将其放入startup.pl中可以解决这个问题),但没有任何看起来与我的问题相符的内容。
有人能证实这一点吗?或者,有人能证实他们网站上的mod_perl + DBD :: Oracle + oracle LDAP名称解析器工作吗?当前,我可以通过不使用LDAP名称适配器来解决问题,但我宁愿在投入生产之前修复它。