In 2005, it was sufficient to setup %ENV in a BEGIN block *BEFORE*
loading DBD::Oracle:
#!/usr/bin/perl -T
use strict;
use warnings;
BEGIN {
$ENV{'ORACLE_HOME'}='/some/where/on/the/disk';
}
use DBI;
# ...
my $dbh=DBI->connect('dbi:Oracle:...',$user,$pass);
# ...
The trick was that DBI loads DBD/Oracle.pm, which loads DBD::Oracle.xs,
which loads the Oracle client libraries, which need %ENV set up
properly. Until the point where the Oracle client libraries are loaded,
the %ENV did (and does) not matter.
Note that %ENV is set up in a BEGIN block before use DBI, just in case
DBI would load DBD::Oracle (and thus the Oracle client libraries). If I
was really paranoid, I would write
BEGIN {
$ENV{'ORACLE_HOME'}='/some/where/on/the/disk';
require DBI;
}
instead, just in case DBI would load DBD::Oracle before connect() was
called.
And regarding Apache: Apache DOES NOT pass its environment to its child
processes unmodified, instead, it removes most environment variables. To
pass a variable from Apaches environment to a child process (CGI), you
have to specify it in the Apache configuration in a "PassEnv" directive,
i.e. "PassEnv ORACLE_HOME". It should also be possible to use "SetEnv
ORACLE_HOME /some/where/on/the/disk".
See also
<http://www.alexander-foken.de/Censored%20copy%20of%20Oracle%20Troubleshooter%20HOWTO.html>,
which is written for a Windows-based DBI application accessing an Oracle
database, but except for the backslashes and the DLL suffix, most of it
is also true for DBI applications on Unix-like systems.
Alexander
On 10.01.2009 14:16, Alexander V Alekseev wrote:
Hello!
On Fri, 9 Jan 2009, Koester, Chris wrote:
Scripts ran from cron give this error.
failed: ERROR OCIEnvNlsCreate. Check ORACLE_HOME (Linux) env var or
PATH (Windows) and or NLS settings, permissions, etc. at
/app/XOstats/prod/bin/util/check_user.pl line 43
Can't call method "disconnect" on an undefined value at
/app/XOstats/prod/bin/util/check_user.pl line 69.
Web log give this error.
[Fri Jan 09 12:08:57 2009] [error] [client 172.31.48.85] Premature
end of script headers: Login.pl
[Fri Jan 09 12:21:39 2009] [error] [client 172.31.48.85]
install_driver(Oracle) failed: Can't load
'/xst/xstlocal/bin/lib/perl5/site_perl/5.10.0/i86pc-solaris-thread-multi/auto/DBD/Oracle/Oracle.so'
for module DBD::Oracle: ld.so.1: perl: fatal: libnnz10.so: open
failed: No such file or directory at
/xst/xstlocal/bin/lib/perl5/5.10.0/i86pc-solaris-thread-multi/DynaLoader.pm
line 203.
For some reason its not recognizing the $ENV{…. } set with in the perl
scripts to identify ORACLE_HOME and other variables.
Most ld.so implementations read environment only once. When your
application is loaded, ld.so is initialized first, therefore you usually
cannot change it's environment from your code.
$ENV{"ORACLE_HOME"}="/xst/xstlocal/bin/oracleInstantClient/instantclient_10_2";
$ENV{"TNS_ADMIN"}="/xst/xstlocal/bin/oracleInstantClient/instantclient_10_2";
$ENV{"LD_LIBRARY_PATH"}="/xst/xstlocal/bin/oracleInstantClient/instantclient_10_2:....
If I have the script from the command line with all the env variables
set correctly the script runs. It basically does not recognize the
variables in the scripts.
The best way to solve the problem is to set environment before
http server starts. (for example in its startup script).
If you do not have access to httpd startup, and your script is
pure CGI (not FastCGI, not mod_perl, etc...), you can put something like
this to your script:
-------------------------------
#!/usr/bin/perl
BEGIN {
if (not $ENV{"MYLIBSET"} and (not $ENV{"LD_LIBRARY_PATH"} or
$ENV{"LD_LIBRARY_PATH"} !~
m#/xst/xstlocal/bin/oracleInstantClient/instantclient_10_2#)) {
$ENV{"LD_LIBRARY_PATH"}="/xst/xstlocal/bin/oracleInstantClient/instantclient_10_2:....";
$ENV{"MYLIBSET"} = 1; # Just in case someone mangles
LD_LIBRARY_PATH in/after exec()
exec($0,@ARGV);
}
}
-------------------------------
It's ugly, but works.
Bye. Alex.
--
Alexander Foken
mailto:alexan...@foken.de http://www.foken.de/alexander/